#!/usr/local/bin/python2.7
# encoding: utf-8
'''
NervuresDesignTool -- Outil de conception/simulation de parapentes Nervures

Classe xxx
Description :
@module : gui.graphicsbase.common
@author:      puiseux
@copyright:   2013 Nervures. All rights reserved.      
@license:    LGPL
@contact:    be@nervures.com, pierre@puiseux.name
@deffield    creation: 10 févr. 2013
'''
import sys, os, math
from PyQt4 import QtCore, QtGui
import numpy as np
from scipy import interpolate
from utilitaires.utilitaires import whoami, trace, dist
from utilitaires.path import Path
# from inout.lecteur import LecteurGnuplot
# from inout.lecteurdxf import LecteurDXFNervures
# from inout.lecteurnervures import LecteurNervures
# from config import VALIDATION_DIR


            
def polygonFromPoints(points):
    """
    Paramètres:
    ----------
    - points peut être : 
        * une liste ou un tuple de (xi,yi), 
        * une liste ou un tuple de QPointF, 
        * un np.ndarray, de shape (n,2), p.ex. [(x1,y1), (x2,y2), ...].
            si points est de shape (N,d) avec d>2, seules les coordonnées (i,0) et (i,1) 0<=i<N sont utilisées
        * un nom de fichier 
    Retourne :
    --------
    - un QPolygon a partir de points.
    TODO: 
    ----
    - traiter les cas ou points est un QPolygon
    """
    if points is None or points == [] : 
        return QtGui.QPolygonF()
    if isinstance(points, (QtGui.QPolygonF)) :
        return points
    if isinstance(points, (list, tuple, np.ndarray)) :
#         for point in points : trace('', point, len(point))
        if len(points) == 0 : 
            return QtGui.QPolygonF()
        if isinstance(points[0], QtCore.QPointF) : 
            qpointfs = points
        else :
            qpointfs = [QtCore.QPointF(point[0], point[1]) for point in points]
        poly = QtGui.QPolygonF(qpointfs)
        return poly
    if isinstance(points, (str, unicode, QtCore.QString, )):#fichier
        try :
            file_ = unicode(points)
            file_ = Path(file_)
            ext = file_.ext.lower()
            #trace(self, "lecture sur %s"%file_)
            if ext in ('.dxf',) :
                lecteur = LecteurDXFNervures(file_)
                polygon = lecteur.lire()
                return polygonFromPoints(polygon)#recursif...
            elif ext in ('.gnu', ) :
                lecteur = LecteurGnuplot(file_, patch=False)
                lecteur.dim = 2
                lecteur.patch = False
                polygon = lecteur.lire()
                return polygonFromPoints(polygon)#recursif...
            elif ext in ('.pts') :
#                 print "+++++++"
                lecteur = LecteurNervures(file_)
                polygon = lecteur.lire()
                print type(polygon)
                if lecteur.genre.lower() == 'voile' : 
                    raise IOError(whoami()+u"%s n'est pas un polygon2d mais 3d (voile?, profil3d?)"%file_.name)
                elif lecteur.dimension == 3 :
                    polygon = lecteur.points[:,:-1]
#                     trace(None, polygon.shape)
                return polygonFromPoints(polygon)#recursif...
                    
        except Exception as msg: 
            raise IOError(msg)
        return polygon    
    else : 
        raise TypeError(u"%s, cas non implémenté"%whoami())
    
pointsTopolygon = polygonFromPoints
def pointsFromPolygon(qpolygon, close=True):
    '''
    fonction inverse de polygonFromPoints()
    Paramètres:
    ----------
    - un QPolygon de taille N
    Retourne :
    --------
    - points : np.ndarray, de shape 
        - (N,2) si close==False
        - (N+1,2) si close==True, ou le point supplémentaire est le premier point (de sorte que points[0]=points[-1]
    '''
    if qpolygon is None or qpolygon.size()==0: return np.zeros((0,2))
    else : N = qpolygon.size()
    first = qpolygon[0].x(), qpolygon[0].y()
    last = qpolygon[N-1].x(), qpolygon[N-1].y()
    close = close and dist(first, last) > 1.0e-8
    if close : N += 1
    points = np.zeros((N, 2))
    for k, qpoint in enumerate(qpolygon) :
        points[k] = qpoint.x(), qpoint.y()
    if close  : 
        points[-1] = points[0]
    return points
polygonToPoints = pointsFromPolygon

def p2t(qpoint):
    """ retourne les coord d'un QPointF sous forme de tuple simple"""
    return (qpoint.x(), qpoint.y())

def p2s(qpoint):
    """ retourne les coord d'un QPointF sous forme de chaine"""
    return '(%.2f, %.2f)'%(qpoint.x(), qpoint.y())

def p2a(qpoint):
    """ retourne les coord d'un QPointF sous forme de np.ndarray((1,2))"""
    return np.asarray((qpoint.x(), qpoint.y())).reshape((1,2))


#def dist2(p1, p2, n=2):
#    '''retourne le carré de la distance de p1 à p2 en norme n=2'''
#    if isinstance(p1, QtCore.QPointF) : x1, y1 = p1.x(), p1.y()
#    else : x1, y1 = p1[0], p1[1]
#    if isinstance(p2, QtCore.QPointF) : x2, y2 = p2.x(), p2.y()
#    else : x2, y2 = p2[0], p2[1]
#    return (x2-x1)**2+(y2-y1)**2
#    
#def dist(p1, p2, n=2):
#    '''retourne la distance de p1 à p2 en norme n=2'''
#    return math.sqrt(dist2(p1, p2))

if __name__ == '__main__':
    for filename in ('ARBIZON.PTS', 'diamirE.pts', 'diamirM.pts'):#,'diamir.pts') :
        path =  Path(VALIDATION_DIR, 'formatpts',filename)
        print ' :\n******************\n %s :\n******************'%path.name
        print polygonFromPoints(path)


